﻿#region Copyright
// Copyright (c) 2011-2012 RaisingForce Team (Alikin Sergey)
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion

using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Windows;
using RaisingForce.Raise.Presentation.ViewModel;

namespace RaisingForce.Raise.Presentation.Controls
{
    public abstract class ModelWindowBase :
        Window
    {
        #region Constructors

        public ModelWindowBase()
            : base()
        { }

        #endregion

        #region Result Class

        public class Result
        {
            private readonly ModelWindowBase window;

            public ModelWindowBase Window
            {
                get
                {
                    Contract.Ensures(Contract.Result<ModelWindowBase>() != null);
                    return this.window;
                }
            }

            private readonly bool success;

            public bool Success
            {
                get { return this.success; }
            }

            public Result(ModelWindowBase window, bool success)
            {
                Contract.Requires(window != null);
                this.window = window;
                this.success = success;
            }
        }

        #endregion

        #region Private Declarations

        private WindowViewModel contentViewModel;

        private void windowCloseHandler(object sender, EventArgs e)
        {
            this.Close();
        }

        #endregion

        #region Protected Declarations

        protected void SetupContent(WindowViewModel content)
        {
            if (content == null)
            {
                throw new ArgumentNullException("content");
            }
            Contract.EndContractBlock();
            this.contentViewModel = content;
            this.Closed += (s, e) => this.contentViewModel.RequestClose -= this.windowCloseHandler;
            content.RequestClose += this.windowCloseHandler;
            content.DialogResultChanged +=
                (s, e) => this.DialogResult = ((WindowViewModel)s).DialogResult;
            this.Title = content.DisplayName;
        }

        #endregion

        #region Show Static Method

        public static Result Show(
            ModelWindowBase window,
            ModelWindowShowMode showMode = ModelWindowShowMode.Normal,
            Window owner = null,
            double width = 0,
            double height = 0,
            WindowStartupLocation startupLocation = WindowStartupLocation.CenterOwner,
            bool showInTaskbar = true,
            Action<Window> prologAction = null)
        {
            if (window == null)
            {
                throw new ArgumentNullException("window");
            }
            Contract.Requires(Enum.IsDefined(typeof(ModelWindowShowMode), showMode));
            Contract.Requires(Enum.IsDefined(typeof(WindowStartupLocation), startupLocation));
            Contract.Ensures(Contract.Result<Result>() != null);
            Contract.EndContractBlock();
            bool isEmulation = IsEmulation(showMode);
            if (!isEmulation)
            {
                window.Owner = owner;
                window.WindowStartupLocation = startupLocation;
                window.ShowInTaskbar = showInTaskbar;
                if (width > 0)
                {
                    window.Width = width;
                }
                if (height > 0)
                {
                    window.Height = height;
                }
            }
            if (prologAction != null)
            {
                prologAction(window);
            }
            bool success;
            switch (showMode)
            {
                case ModelWindowShowMode.Normal:
                    window.Show();
                    success = true;
                    break;
                case ModelWindowShowMode.Dialog:
                    success = window.ShowDialog() == true;
                    break;
                case ModelWindowShowMode.EmulateOk:
                    success = true;
                    break;
                case ModelWindowShowMode.EmulateCancel:
                    success = false;
                    break;
                default:
                    Debug.Fail("Invalid ModelWindowShowMode value: " + showMode.ToString());
                    success = false;
                    break;
            }
            if (isEmulation)
            {
                window.Close();
            }
            return new Result(window, success);
        }

        #endregion

        #region Emulation Support Static Declarations

        public static ModelWindowBase CreateEmulationWindow()
        {
            Contract.Ensures(Contract.Result<ModelWindowBase>() != null);
            return new EmulationWindow();
        }

        public static bool IsEmulation(ModelWindowShowMode showMode)
        {
            Contract.Requires(Enum.IsDefined(typeof(ModelWindowShowMode), showMode));
            bool result;
            switch (showMode)
            {
                case ModelWindowShowMode.Normal:
                case ModelWindowShowMode.Dialog:
                    result = false;
                    break;
                case ModelWindowShowMode.EmulateOk:
                case ModelWindowShowMode.EmulateCancel:
                    result = true;
                    break;
                default:
                    Debug.Fail(string.Format("Unknown ModelWindowShowMode value: {0}", showMode.ToString()));
                    result = false;
                    break;
            }
            return result;
        }

        #endregion
    }
}
